<?php
namespace app\common\service;

use app\admin\model\Hook;
use app\admin\model\HookPlugin;
use app\admin\model\Plugin;
use think\facade\Cache;
use think\Service;


class PluginService extends Service
{
    public function boot()
    {
        $hookMap = $this->scanPlugins(root_path() . 'plugins');

        $this->app->event->listenEvents($hookMap);
    }
    public function registerPlugin()
    {
        $hook_plugins = Cache::get('hook_plugins');
        $hooks = Cache::get('hooks');
        $plugins = Cache::get('plugins');

        if (!$hook_plugins) {
            // 所有钩子
            $hooks = Hook::where('status', 1)->column('status', 'name');
            // 所有插件
            $plugins = Plugin::where('status', 1)->column('status', 'name');
            // 钩子对应的插件
            $hook_plugins = HookPlugin::where('status', 1)->order('hook,sort')->select();
            // 非开发模式，缓存数据
            if (config('develop_mode') == 0) {
                Cache::set('hook_plugins', $hook_plugins);
                Cache::set('hooks', $hooks);
                Cache::set('plugins', $plugins);
            }
        }
        if ($hook_plugins) {
            foreach ($hook_plugins as $value) {
                if (isset($hooks[$value['hook']]) && isset($plugins[$value['plugin']])) {
                    if (class_exists("\\plugins\\" . $value['plugin'] . '\\' . $value['plugin'])) {
                        $this->app->event->listen($value['hook'], "\\plugins\\" . $value['plugin'] . '\\' . $value['plugin']);
                    }
                }
            }
        }

    }
    /**
     * 扫描插件目录，收集所有插件的钩子信息
     * @param string $pluginDir 插件目录路径
     * @return array 钩子到命名空间的映射数组
     */
    function scanPlugins(string $pluginDir = __DIR__ . '/plugins'): array
    {
        $hookMap = [];
        $dirIterator = new \RecursiveDirectoryIterator($pluginDir);
        $iterator = new \RecursiveIteratorIterator($dirIterator);

        foreach ($iterator as $fileInfo) {
            if ($fileInfo->isFile() && $fileInfo->getExtension() === 'php') {
                $className = $fileInfo->getBasename('.php');
                $dirName = $fileInfo->getPathInfo()->getBasename();

                // 检查文件夹名称和类文件名称是否匹配
                if ($className === $dirName) {
                    $filePath = $fileInfo->getPathname();
                    require_once $filePath;

                    // 获取类的命名空间
                    $namespace = $this->getClassNamespace($filePath);
                    $fullClassName = $namespace ? $namespace . '\\' . $className : $className;

                    // 检查类是否存在并实例化
                    if (class_exists($fullClassName)) {
                        try {
                            $reflection = new \ReflectionClass($fullClassName);
                            $instance = $reflection->newInstanceWithoutConstructor();

                            // 检查是否有$hooks属性
                            if (isset($instance->hooks) && is_array($instance->hooks)) {
                                foreach ($instance->hooks as $key => $hook) {
                                    if (is_string($key)) {
                                        $hook = $key;
                                    }
                                    $hookMap[$hook][] = $fullClassName;
                                }
                            }
                        } catch (\ReflectionException $e) {
                            // 记录错误但继续处理其他插件
                            error_log("Failed to instantiate plugin class: {$fullClassName} - {$e->getMessage()}");
                        }
                    }
                }
            }
        }

        return $hookMap;
    }

    /**
     * 从PHP文件中提取类的命名空间
     * @param string $filePath PHP文件路径
     * @return string 命名空间，如果没有则为空字符串
     */
    function getClassNamespace(string $filePath): string
    {
        $namespace = '';
        $content = file_get_contents($filePath);

        if (preg_match('/namespace\s+([^;]+);/', $content, $matches)) {
            $namespace = trim($matches[1]);
        }

        return $namespace;
    }


}